#include "ty_ble.h"
#include "tuya_ble_api.h"
#include "tuya_ble_ota.h"
#include "tuya_ble_utils.h"
#include "app.h"
#include "app_log.h"
#include "tuya_ble_sdk_demo.h"
#include "app_utils.h"
#include "app_task.h"


/*********************************************************************
 * CONSTANT
 */
#define BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED           0

#define     DEFAULT_ADV_DATA    \
            {                   \
                3,              \
                {               \
                    0x02,       \
                    0x01,       \
                    0x06,       \
                },              \
            }
            
#define     DEFAULT_SCAN_RSP    \
            {                   \
                13,              \
                {               \
                    0x0C,       \
                    0x09,       \
                    't', 'y', '_', 'b', 'l', 'e', '_', 'd', 'e', 'm', 'o', \
                },              \
            }

#define     DEFAULT_ADV_PARAM               \
            {                               \
                .adv_interval_min = TY_ADV_INTERVAL,    \
                .adv_interval_max = TY_ADV_INTERVAL,    \
                .adv_type         = 0x03,   \
                .adv_power        = 0x00,   \
                .adv_channal_map  = 0x07,   \
            }

/*********************************************************************
 * STRUCT
 */

/*********************************************************************
 * VARIABLE
 */
static ty_ble_data_t        s_adv_data  = DEFAULT_ADV_DATA;
static ty_ble_data_t        s_scan_rsp  = DEFAULT_SCAN_RSP;
static ty_ble_adv_param_t   s_adv_param = DEFAULT_ADV_PARAM;

static bool is_advertising = false;

extern const struct ke_task_desc TASK_DESC_APP;

/*********************************************************************
 * FUNCTION
 */
static void ty_ble_adv_init(void)
{
    adv_cfg_t adv_cfg;
    adv_cfg.adv_data_len = s_adv_data.len;
    memcpy(adv_cfg.adv_data, s_adv_data.value, s_adv_data.len);
    adv_cfg.res_data_len = s_scan_rsp.len;
    memcpy(adv_cfg.res_data, s_scan_rsp.value, s_scan_rsp.len);
    adv_cfg.adv_interval = MSEC_TO_UNITS(s_adv_param.adv_interval_max, UNIT_0_625_MS);
    adv_cfg.adv_timeout = MSEC_TO_UNITS(BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED, UNIT_10_MS);
    adv_cfg.adv_type = s_adv_param.adv_type;
    adv_cfg.adv_power = s_adv_param.adv_power;
    adv_cfg.channel_map = s_adv_param.adv_channal_map;
    app_adv_init(&adv_cfg);
}

/*********************************************************
FN: 
*/
uint32_t ty_ble_init(void)
{
    // Create APP task
    ke_task_create(TASK_APP, &TASK_DESC_APP);

    // Initialize Task state
    ke_state_set(TASK_APP, APPM_INIT);

    nvds_tag_len_t addr_len = 6;
    uint8_t addr[6];
    if (nvds_get(NVDS_TAG_BD_ADDRESS, &addr_len, app_env.addr.addr.addr) != NVDS_OK)
    {
        tuya_ble_str_to_hex((uint8_t*)TY_DEVICE_MAC, MAC_STRING_LEN, addr);
        for (int i = 0; i < 6; i++)
        {
            app_env.addr.addr.addr[i] = addr[5-i];
        }
        nvds_put(NVDS_TAG_BD_ADDRESS, 6, app_env.addr.addr.addr);
        log_debug("[OM] put NVDS_TAG_BD_ADDRESS\n");
    }
    log_debug_array_ex("[OM] MAC", app_env.addr.addr.addr, 6);

#if (BLE_APP_SEC)
    app_sec_init();
#endif

#if (BLE_APP_CENTRAL_SUPPORT)
    app_central_init();
#endif

    ty_ble_adv_init();

    return 0;
}

/*********************************************************
FN: 
*/
uint32_t ty_ble_start_adv(void)
{
    app_adv_start_gen();
    return 0;
}

/*********************************************************
FN: 
*/
uint32_t ty_ble_restart_adv(void)
{
    app_adv_start_gen();
    return 0;
}

/*********************************************************
FN: 
*/
uint32_t ty_ble_stop_adv(void)
{
    app_adv_stop();
    return 0;
}

/*********************************************************
FN: 
*/
uint32_t ty_ble_set_advdata_and_scanrsp(const ty_ble_data_t* p_adv_data, const ty_ble_data_t* p_scan_rsp)
{
    adv_cfg_t cfg = {0};
    if (p_adv_data != NULL)
    {
        cfg.adv_data_len = p_adv_data->len;
        memcpy(cfg.adv_data, p_adv_data->value, p_adv_data->len);
    }
    if (p_scan_rsp != NULL)
    {
        cfg.res_data_len = p_scan_rsp->len;
        memcpy(cfg.res_data, p_scan_rsp->value, p_scan_rsp->len);
    }
    app_adv_set_adv_data_and_scan_resp_data(&cfg);
    // app_adv_start_gen();
    return 0;
}

/*********************************************************
FN: 
*/
uint32_t ty_ble_set_adv_param(const ty_ble_adv_param_t* p_param)
{
    adv_cfg_t cfg = {0};
    cfg.adv_interval = MSEC_TO_UNITS(p_param->adv_interval_max, UNIT_0_625_MS);
    cfg.adv_timeout = MSEC_TO_UNITS(BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED, UNIT_10_MS);
    cfg.adv_type = p_param->adv_type;
    // adv_cfg.adv_power = s_adv_param.adv_power;
    // adv_cfg.channel_map = s_adv_param.adv_channal_map;
    app_adv_set_adv_param(&cfg);
    // app_adv_start_gen();
    return 0;
}

/*********************************************************
FN: 
*/
uint32_t ty_ble_connect(const ty_ble_mac_t* p_mac)
{
    return 0;
}

/*********************************************************
FN: 
*/
uint32_t ty_ble_reconnect(const ty_ble_mac_t* p_mac)
{
    return 0;
}

/*********************************************************
FN: 
*/
uint32_t ty_ble_disconnect(void)
{
    appm_disconnect(0, CO_ERROR_REMOTE_USER_TERM_CON);
    return 0;
}

/*********************************************************
FN: 
*/
uint32_t ty_ble_set_conn_param(uint16_t cMin, uint16_t cMax, uint16_t latency, uint16_t timeout)
{
    struct gapc_conn_param param;
    param.intv_min = MSEC_TO_UNITS(cMin, UNIT_1_25_MS);
    param.intv_max = MSEC_TO_UNITS(cMax, UNIT_1_25_MS);
    param.latency = latency;
    param.time_out  = MSEC_TO_UNITS(timeout, UNIT_10_MS);
    appm_update_param(0, &param);
    return 0;
}

/*********************************************************
FN: 
*/
uint32_t ty_ble_set_mac(const ty_ble_mac_t* p_mac)
{
    // bd_addr_t addr;
    // memcpy(addr.addr, p_mac->addr, 6);
    // gapm_set_bdaddr(&addr);
    // app_adv_start_gen();
    app_env.addr.addr_type = p_mac->type;
    memcpy(app_env.addr.addr.addr, p_mac->addr, 6);
    return 0;
}

/*********************************************************
FN: 
*/
uint32_t ty_ble_get_mac(ty_ble_mac_t* p_mac)
{
    p_mac->type = app_env.addr.addr_type;
    memcpy(p_mac->addr, app_env.addr.addr.addr, 6);
    return 0;
}

/*********************************************************
FN: 
*/
uint32_t ty_ble_connect_handler(void)
{
    is_advertising = false;
    tuya_ble_connected_handler();
    return 0;
}

/*********************************************************
FN: 
*/
uint32_t ty_ble_disconnect_handler(void)
{
    tuya_ble_disconnected_handler();
    tuya_ble_ota_disconn_handler();
    return 0;
}

/*********************************************************
FN: 
*/
uint32_t ty_ble_receive_data_handler(const uint8_t* buf, uint32_t size)
{
    tuya_ble_gatt_receive_data((void*)buf, size);
    return 0;
}

/*********************************************************
FN: 
*/
uint32_t ty_ble_send_data(const uint8_t* buf, uint32_t size)
{
    app_ty_server_send_data(0, (uint8_t*)buf, size);
    return 0;
}

/*********************************************************
FN: 
*/
uint32_t ty_ble_get_rssi(int8_t* p_rssi)
{
    return 0;
}

/*********************************************************
FN: 
*/
uint32_t ty_ble_set_tx_power(int8_t tx_power)
{
    return 0;
}

/*********************************************************
FN: 
*/
uint32_t ty_ble_set_device_name(const uint8_t* buf, uint16_t size)
{
    return 0;
}

/*********************************************************
FN: 
*/
uint32_t ty_ble_get_device_name(uint8_t* buf, uint16_t* p_size)
{
    return 0;
}

/*********************************************************
FN: 
*/
uint32_t ty_ble_set_dle(void)
{
    return 0;
}
